package com.jswl.training.springjpa.frame;

import io.netty.buffer.ByteBuf;

/**
 * 用于存放导航部7B协议约定中的一些固定数据
 */
public  class InternalShared {
    //region Fields

    /**
     * 帧尾标志
     */
    public static final byte FRAME_FINISH_FLAG = 0x00;

    /**
     * 数据帧特殊标志0x7B
     */
    public static final byte UNIQUE_FLAG = 0x7B;

    /**
     * 数据帧内容中出现连续两个特殊标志时需要添加的无意义分割数据
     */
    public static final byte PREVENT_HEADER_FLAG = (byte) 0xAA;

    /**
     * 信息类型可用值数组
     */
    private static final byte[] AVAILABLE_INFO_TYPE = new byte[]
            {
                    (byte) 0xA1,
                    (byte) 0xA2,
                    (byte) 0xA3
            };

    /**
     * 帧头字节数组
     */
    public static final byte[] FRAME_HEADER_BYTES = new byte[]
            {
                    InternalShared.UNIQUE_FLAG,
                    InternalShared.UNIQUE_FLAG,
                    InternalShared.UNIQUE_FLAG
            };

    /**
     * 帧头+信源+信宿+信息类型+校验+帧尾 的长度
     */
    public static final int FRAME_SHELL_SIZE = InternalShared.FRAME_HEADER_BYTES.length + 2 + 2 + 1 + 1 + 1;

    //endregion

    //region Public Methods

    /**
     * 检查输入的数据是否是有效的信息类型
     *
     * @param value 数据值
     * @return 数据值是否有效
     */
    public static boolean isValidInfoType(byte value) {
        for (byte v : AVAILABLE_INFO_TYPE) {
            if (v == value) {
                return true;
            }
        }
        return false;
    }

    /**
     * 生成数据帧检验校验值
     *
     * @param frame 数据帧实例
     * @return 校验值
     */
    public static byte computeCheckSum(Nav7BFrame frame) {
        byte checksum = 0;
        byte[] temp = new byte[2];

        checksum ^= frame.getSourcePrimaryId();
        checksum ^= frame.getSourceSecondaryId();

        checksum ^= frame.getTargetPrimaryId();
        checksum ^= frame.getTargetSecondaryId();

        checksum ^= frame.getInfoType();

        intToBytes(frame.getInfoLength(), temp);
        checksum ^= temp[0];
        checksum ^= temp[1];

        intToBytes(frame.getDataType(), temp);
        checksum ^= temp[0];
        checksum ^= temp[1];

        intToBytes(frame.getBitLength(), temp);
        checksum ^= temp[0];
        checksum ^= temp[1];

        ByteBuf buff = frame.getDataContent();
        buff.readerIndex(0);//确保readerIndex从头开始
        while(buff.readableBytes() > 0) {
            checksum ^= buff.readByte();
        }
        buff.readerIndex(0);//重新将readerIndex设置为0
        return checksum;
    }

    //endregion

    //region Private Methods

    /**
     * 将两字节数据转换为数组
     *
     * @param n     数值
     * @param bytes 输出的数组
     */
    private static void intToBytes(int n, byte[] bytes) {
        bytes[0] = (byte) (n & 0xff);
        bytes[1] = (byte) (n >> 8 & 0xff);
    }

    //endregion
}

